package net.mfjassociates.tools;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.log4j.Logger;
import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.nodes.RemarkNode;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.nodes.TextNode;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

public class TestHttpClient {
	
	/**
	 * 
	 */
	private static Logger log=Logger.getLogger(TestHttpClient.class);
	public TestHttpClient() {
		PromptLogin frame = new PromptLogin();
		Properties p=new Properties();
		String propfile=System.getProperty("user.home")+"/.testhttp";
		try {
			p.load(new FileInputStream(propfile));
		} catch (FileNotFoundException e) {
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.username=p.getProperty("username");
		this.password=p.getProperty("password");
		if (this.username!=null) frame.setUsername(new String(Base64.toBytes(username)));
		if (this.password!=null) frame.setPassword(new String(Base64.toBytes(password)));
		PromptLogin.setupGUI(frame);
		this.username=frame.getUsername();
		this.password=frame.getPassword();
		p.setProperty("username", Base64.toString(username.getBytes()));
		p.setProperty("password", Base64.toString(password.getBytes()));
		try {
			p.store(new FileOutputStream(propfile), "# written by TestHttpClient");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private String username;
	private String password;

	/**
	 * @param args
	 * @throws IOException
	 * @throws ClientProtocolException
	 * @throws ParserException
	 * @throws URISyntaxException
	 */
	public static void main(String[] args) throws ClientProtocolException,
			IOException, ParserException, URISyntaxException {
		TestHttpClient tc = new TestHttpClient();
		tc.processRbc();
	}
	interface NodeHandler {
		Object displayNode(String document);
	}
	class LoginLinkNodeHandler implements TestHttpClient.NodeHandler {

		@Override
		public Object displayNode(String document) {
			Parser parser;
			NodeFilter filter;

			try {
				parser = new Parser();
				filter = new TagNameFilter("a");
				parser.setFeedback(Parser.STDOUT);
				Parser.getConnectionManager().setMonitor(parser);
				parser.setResource(document);
				NodeList nl = parser.parse(filter);
				NodeIterator i = null;
				for (i = nl.elements(); i.hasMoreNodes();) {
					Node n = i.nextNode();
					if (n instanceof TagNode) {
						NodeFilter filter2 = new TagNameFilter("input");
						TagNode tn = (TagNode) n;
						NodeList children=tn.getChildren();
						if (children!=null) {
							NodeList text=children.extractAllNodesThatMatch(new NodeClassFilter(TextNode.class));
							if (text!=null) {
								for (NodeIterator i2=text.elements();i2.hasMoreNodes();) {
									TextNode tn1=(TextNode) i2.nextNode();
									if (tn1.getText().toUpperCase().contains("SIGN IN")) return tn.getAttribute("href");
								}
							}
						}
					} else {
						throw new ParserException(
								"a tag encountered but it was not a TagNode class");
					}
				}
				// System.out.println(parser.parse(filter));
			} catch (ParserException e) {
				e.printStackTrace();
			}
			return null;
		}
	}
	class LoginFormNodeHandler implements TestHttpClient.NodeHandler {

		@Override
		public Object displayNode(String document) {
			Parser parser;
			NodeFilter filter;

			try {
				parser = new Parser();
				filter = new AndFilter(new TagNameFilter("form"),
						new HasAttributeFilter("name", "rbunxcgi"));
				parser.setFeedback(Parser.STDOUT);
				Parser.getConnectionManager().setMonitor(parser);
				parser.setResource(document);
				NodeList nl = parser.parse(filter);
				NodeIterator i = null;
				for (i = nl.elements(); i.hasMoreNodes();) {
					Node n = i.nextNode();
					if (n instanceof TagNode) {
						TagNode formtag = (TagNode) n;
						NodeFilter filter2 = new TagNameFilter("input");
						NodeList inputs = new NodeList();
						formtag.collectInto(inputs, filter2);
						List<NameValuePair> qparams = new ArrayList<NameValuePair>();
						for (NodeIterator i2 = inputs.elements(); i2.hasMoreNodes();) {
							Node n2 = i2.nextNode();
							if (n instanceof TagNode) {
								TagNode tn2 = (TagNode) n2;
								System.out.println("input name='"
										+ tn2.getAttribute("name") + "' value='"
										+ tn2.getAttribute("value") + "'");
								String name=tn2.getAttribute("name");
								String value=tn2.getAttribute("value");
								if (name.equals("RSA_DEVPRINT")) value="version%253D1%2526pm%255Ffpua%253Dmozilla%252F5%252E0%2520%2528windows%253B%2520u%253B%2520windows%2520nt%25206%252E1%253B%2520en%252Dus%253B%2520rv%253A1%252E9%252E2%252E16%2529%2520gecko%252F20110319%2520firefox%252F3%252E6%252E16%257C5%252E0%2520%2528Windows%253B%2520en%252DUS%2529%257CWin32%2526pm%255Ffpsc%253D24%257C1280%257C1024%257C1024%2526pm%255Ffpsw%253D%257Cqt1%257Cqt2%257Cqt3%257Cqt4%257Cqt5%257Cqt6%257Cpdf%257Cdef%257Cswf%2526pm%255Ffptz%253D%252D4%2526pm%255Ffpln%253Dlang%253Den%252DUS%257Csyslang%253D%257Cuserlang%253D%2526pm%255Ffpjv%253D0%2526pm%255Ffpco%253D1";
								if (name.equals("K1")) value=username;
								if (name.equals("Q1")) value=password;
								qparams.add(new BasicNameValuePair(name, value));
								// K1 = card number
								// Q1 = password
							} else {
								throw new ParserException(
										"input tag encountered but it was not a TagNode class");
							}
						}
						qparams.add(new BasicNameValuePair("***LOGIN URL***",formtag.getAttribute("action")));
						return qparams;
					} else {
						throw new ParserException(
								"form tag encountered but it was not a TagNode class");
					}
				}
				// System.out.println(parser.parse(filter));
			} catch (ParserException e) {
				e.printStackTrace();
			}
			return null;
		}

	}

	class PostNodeHandler implements TestHttpClient.NodeHandler {

		@Override
		public Object displayNode(String document) {
			Parser parser;
			NodeFilter filter;

			try {
				parser = new Parser();
				filter = new TagNameFilter("a");
				parser.setFeedback(Parser.STDOUT);
				Parser.getConnectionManager().setMonitor(parser);
				parser.setResource(document);
				NodeList nl = parser.parse(filter);
				NodeIterator i = null;
				for (i = nl.elements(); i.hasMoreNodes();) {
					Node n = i.nextNode();
					if (n instanceof TagNode) {
						NodeFilter filter2 = new TagNameFilter("input");
						TagNode tn = (TagNode) n;
						NodeList children=tn.getChildren();
						if (children!=null) {
							NodeList text=children.extractAllNodesThatMatch(new NodeClassFilter(TextNode.class));
							if (text!=null) {
								for (NodeIterator i2=text.elements();i2.hasMoreNodes();) {
									TextNode tn1=(TextNode) i2.nextNode();
									if (tn1.getText().toUpperCase().contains("SIGN IN")) return tn.getAttribute("href");
								}
							}
						}
					} else {
						throw new ParserException(
								"a tag encountered but it was not a TagNode class");
					}
				}
				// System.out.println(parser.parse(filter));
			} catch (ParserException e) {
				e.printStackTrace();
			}
			return null;
		}
		
	}
	
	void processRbc() throws ClientProtocolException, IOException,
			ParserException, URISyntaxException {

		DefaultHttpClient httpclient = new DefaultHttpClient();
		httpclient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "User-Agent=Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16");

		try {
			/*
			 * httpclient.getCredentialsProvider().setCredentials( new
			 * AuthScope("proxy", 8080), new
			 * UsernamePasswordCredentials("mxj037", new String(Base64
			 * .toBytes("")))); HttpHost proxy = new
			 * HttpHost("proxy", 8080);
			 * httpclient.getParams().setParameter(ConnRoutePNames
			 * .DEFAULT_PROXY, proxy);
			 */
			HttpGet httpget = new HttpGet("http://www.rbc.com/canada.html");
			NodeHandler linkHandler = new LoginLinkNodeHandler();
			String loginLinkUrl=(String) handleUriResponse(httpclient, httpget, linkHandler);
			/*
			 * HttpResponse response = httpclient.execute(httpget); HttpEntity
			 * entity = response.getEntity(); if (entity != null) { InputStream
			 * instream = entity.getContent(); int l; byte[] tmp = new
			 * byte[2048]; while ((l = instream.read(tmp)) != -1) { } }
			 */
			String nextUrl = "https://www1.royalbank.com/cgi-bin/rbaccess/rbunxcgi%3FF6=1%26F7=IB%26F21=IB%26F22=IB%26REQUEST=ClientSignin%26LANGUAGE=ENGLISH";
			httpget = new HttpGet(loginLinkUrl);
			NodeHandler formHandler = new LoginFormNodeHandler();
			String POST_URL=null;
			List<NameValuePair> qparams=(List<NameValuePair>) handleUriResponse(httpclient, httpget, formHandler);
			NameValuePair nameValuePair=null;
			for (Iterator iterator = qparams.iterator(); iterator.hasNext();) {
				nameValuePair = (NameValuePair) iterator.next();
				if (nameValuePair.getName().equals("***LOGIN URL***")) {
					POST_URL=nameValuePair.getValue();
					break;
				}
			}
			qparams.remove(nameValuePair); // remote this ***LOGIN URL***
			UrlEncodedFormEntity entity = new UrlEncodedFormEntity(qparams, "UTF-8");
			URI login=new URI(loginLinkUrl).resolve(POST_URL);
			HttpPost httppost = new HttpPost(login);
			httppost.setEntity(entity);
			// Now, post to login
			NodeHandler postHandler = new PostNodeHandler();
			Object o=handleUriResponse(httpclient, httppost, postHandler);
			int i=0;
		} finally {
			httpclient.getConnectionManager().shutdown();
		}
	}

	Object handleUriResponse(DefaultHttpClient httpclient, HttpUriRequest message, NodeHandler nodeHandler) throws ClientProtocolException, IOException {
		HttpResponse response = httpclient.execute(message);
		ResponseHandler<String> responseHandler = new BasicResponseHandler();
		String responseBody = responseHandler.handleResponse(response);
		// System.out.println(responseBody);
		Object result= nodeHandler.displayNode(responseBody);
		handleClientResponse(httpclient, message.getURI().toString());
		return result;
	}
	private void handleClientResponse(DefaultHttpClient httpclient, String uri) {
		List<Cookie> cookies = httpclient.getCookieStore().getCookies();
		log.debug("Client cookies after transaction for "+uri);
		for (Iterator iterator = cookies.iterator(); iterator.hasNext();) {
			Cookie cookie = (Cookie) iterator.next();
			log.debug(cookie);
		}
		return;
	}

	public void testParser() throws ParserException {
		String url = "http://www.rbc.com";
		NodeFilter filter = null;
		// filter = new TagNameFilter("form");
		NodeList nl = null;
		Parser parser = new Parser(url);
		if (filter != null)
			nl = parser.parse(filter);
		NodeIterator i = null;
		log.debug("processing elements");
		processNodes(parser.elements(), filter);
		log.debug("processing node list");
		if (nl != null)
			processNodes(nl.elements(), filter);
	}

	public void processNodes(NodeIterator i, NodeFilter filter)
			throws ParserException {
		processNodes(i, filter, 1);
	}

	public void processNodes(NodeIterator i, NodeFilter filter, int level)
			throws ParserException {
		for (NodeIterator ii = i; i.hasMoreNodes();) {
			processNode(i.nextNode(), filter, level);
		}
	}

	public void processNode(Node n, NodeFilter filter, int level)
			throws ParserException {
		if (n instanceof TextNode) {
			TextNode tn = (TextNode) n;
			log.debug("Text(" + level + ")='" + tn.getText() + "'");
		}
		if (n instanceof RemarkNode) {
			RemarkNode rn = (RemarkNode) n;
			log.debug("Remark(" + level + ")='" + rn.getText() + "'");
		}
		if (n instanceof TagNode) {
			TagNode tn = (TagNode) n;
			log.debug("Tag name(" + level + ")='" + tn.getTagName()
					+ "'");
			NodeList list = new NodeList();
			if (filter != null) {
				tn.collectInto(list, filter);
			} else {
				list = tn.getChildren();
				if (list == null)
					list = new NodeList();
			}
			processNodes(list.elements(), filter, level + 1);
		}
	}
}
